home *** CD-ROM | disk | FTP | other *** search
/ The Original Shareware 1.1 / The Original Shareware (WeMake CDs)(Volume 1.1)(CDs, Inc)(1993).iso / 6 / unix_cu.zip / CU.C
Text File  |  1986-12-21  |  18KB  |  668 lines

  1. /* WARNING - this program typed in by hand from DECUS source, so beware typos
  2.     such as extra/missing ;'s and what not.  (/ \ | & =)    */
  3. /* Note - the first two arguments to "ioctl" reversed. */
  4. #include <stdio.h>
  5. #include <signal.h>
  6. #include <sgtty.h>
  7. #include <errno.h>
  8. /*
  9.  *  cu telno [-t] [-s speed] [-l line] [-a acu]
  10.  *
  11.  *  -t is for dial-out to terminal.
  12.  *  speeds are: 110, 134, 150, 300, 1200.  300 is default.
  13.  *
  14.  *  Escape with `~' at beginning of line.
  15.  *  Ordinary diversions are ~<, ~> and ~>>.
  16.  *  Silent output diversions are ~>: and ~>>:.
  17.  *  Terminate output diversion with ~> alone.
  18.  *  Quit is ~. and ~! gives local command or shell.
  19.  *  Also ~$ for canned procedure pumping remote.
  20.  *  ~%put from [to]  and  ~%take from [to] invoke builtins
  21.  */
  22. #define CRLF "\r\n"
  23. #define wrc(ds) write(ds,&c,1)
  24. int errno;
  25. int rd_pid, wt_pid;
  26. int sig16cnt;
  27. char    *devcul    = "/dev/cul0";
  28. char    *devcua    = "/dev/cua0";
  29. char    *lspeed    = "300";
  30. int    ln;    /* fd for comm line */
  31. char    tkill, terase;    /* current input kill & erase */
  32. char    c;
  33. char    *connmsg[] = {
  34.     "",
  35.     "line busy",
  36.     "call dropped",
  37.     "no carrier",
  38.     "can't fork",
  39.     "acu access",
  40.     "tty access",
  41.     "tty hung",
  42.     "usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
  43. };
  44. char prompt[16], tk_tmplt[128], pt_tmplt[128];
  45. int pipefd[2];
  46. FILE *pipefp, *fdopen();
  47. int intr;
  48. int dout;
  49. int nhup;
  50.  
  51. sig16()
  52. {
  53.     signal(16, sig16);
  54.     sig16cnt++;
  55. }
  56.  
  57. sig2()
  58. {
  59.     signal(SIGINT, SIG_IGN);
  60.     intr = 1;
  61. }
  62.  
  63. do_macro(string, f)    /* processes system macros for take and put -cwg */
  64.     /* Note - Probably the better way to handle "escape" sequences
  65.     is to use something like "~" rather than "^" as a lead-in.
  66.     This would allow ^ to stand for caret (circumflex) itself,
  67.     ~~ would represent tilde, with lowercase equivalents for the
  68.     specific functions below (e.g., ~v for sync and ~{ for EOF escape).
  69.     Then, ALL control characters could be represented as ~@ ~A ... ~^ ~_. */
  70. char *string;        /* pointer to the macro command string */
  71. int f;            /* fd of input file, used if this is ~%put */
  72. {
  73.     int rcount;
  74.     int sync;    /* whether we have to wait for prompt for ea out ln */
  75.     char *strptr;    /* roving pointer into macro string */
  76.  
  77.     strptr = string;        /* begin at the beginning... */
  78.     sig16cnt = 0;            /* make sure no prev syncs to mess up */
  79.     while (c = *(strptr++)) {    /* while there is more to do... */
  80.         if (c != '~') {        /* if just part of normal string... */
  81.             wrc(ln);    /* send it out,... */
  82.             continue;    /* and do next character */
  83.         }
  84.         if (!(c = *(strptr++))) /* if premature end of string... */
  85.             break;        /* just ignore trailing '~' */
  86.         if (c == '~') {        /* if "~~", send single ~ */
  87.             wrc(ln);
  88.             continue;
  89.         }
  90.         if (c == 'v') {        /* if "~v" (SYN) - synchronize with */
  91.             while (!sig16cnt)    /* rd() process on nxt prompt */
  92.                 sleep(2);
  93.             sig16cnt = 0;    /* reset for next sync */
  94.             continue;
  95.         }
  96.         if (c == '{') {        /* if "~{" (ESC) - divert rd() proc */
  97.             kill(rd_pid, 16);    /* send signal 16 to rd()
  98.                     process to read pipe and divert read */
  99.             strptr += 2;    /* skip over this token */
  100.             while (*(strptr - 2) != '~' && *(strptr - 1) != '}')
  101.                 strptr++;    /* skip to end of EOF */
  102.             continue;
  103.         }
  104.         if (c == 'l') {        /* if "~l" - send lines of in fl */
  105.             strptr++;    /* skip following "~" (we trust) */
  106.             if ((c = *(strptr++)) == 'v')    /* if we must sync */
  107.                 sync = 1;    /* with incoming prompts */
  108.             else
  109.                 sync = 0;
  110.             /*/*/
  111.             intr = 0;
  112.             if (!nhup)
  113.                 signal(SIGINT, sig2);
  114.             mode(2);    /* no raw (catch interrupt) */
  115.             rcount = 0;
  116.             while(!intr && rdc(f) == 1) {
  117.                 rcount++;        /* copy file to line */
  118.                 if (c == tkill || c == terase)
  119.                     wrln("\\");    /* write string to ln */
  120.                 if (wrc(ln) != 1) {
  121.                     xsleep(2);
  122.                     if (wrc(ln) != 1) { /* write c to ln */
  123.                         prf("character missed");
  124.                         intr = 1;
  125.                         break;
  126.                     }
  127.                 }
  128.                 if ((c == '\n') && sync) { /* if we must wait */
  129.                     while (!sig16cnt)    /* for prompt */
  130.                         sleep(1);
  131.                     sig16cnt = 0;        /* next time */
  132.                 }
  133.             }
  134.             signal(SIGINT, SIG_IGN);
  135.             close(f);
  136.             if (intr) {
  137.                 wrln("\n");
  138.                 prf("stopped after %d bytes", rcount);
  139.             }
  140.             mode(1);    /* raw (do not catch interrupt) */
  141.             /*/*/
  142.             continue;
  143.         }
  144.         if (c > '/' && c < ':') {    /* delay spec. 0 - 9 sec's */
  145.             sleep(c - '0');    /* calculate binary integer interval */
  146.             continue;
  147.         }
  148.         if (c == '?') {        /* "~?" (DEL) - send DEL character */
  149.             c = '\177';    /* construct a DEL character */
  150.             wrc(ln);
  151.             continue;
  152.         }
  153.         /* other control characters - interpret and send them. */
  154.         if (c > '?' && c < '`') {    /* if legitimate control ch */
  155.             c -= '@';    /* adjust to the control character */
  156.             wrc(ln);    /* and send it out. */
  157.             continue;
  158.         }
  159.     }        /* end of while loop */
  160. }
  161. rdc(ds) {
  162.     ds = read(ds, &c, 1);
  163.     c &= 0177;
  164.     return(ds);
  165. }
  166. int set14;
  167. xsleep(n)
  168. {
  169.     xalarm(n);
  170.     pause();
  171.     xalarm(0);
  172. }
  173. xalarm(n)
  174. {
  175.     set14 = n;
  176.     alarm(n);
  177. }
  178. sig14()
  179. {
  180.     signal(SIGALRM, sig14);
  181.     if (set14) alarm(1);    /* Set alarm to go off in one second. */
  182. }
  183. /*
  184.  *  main:  get connection, set speed for line.
  185.  *  spawn child to invoke rd to read from line, output to fd 1 (stdout).
  186.  *  main line invokes wr to read tty, write to line.
  187.  */
  188. main(ac, av)
  189. char *av[];
  190. {
  191.     static  char    *sysdesfl = "/etc/unix.cs";
  192.                     /* system description filename string */
  193.     FILE    *sdf;        /* pointer to system description file */
  194.     int fk;
  195.     int speed;
  196.     char *telno;
  197.     struct sgttyb stbuf;
  198.  
  199.     if (pipe(pipefd))    /* if cannot construct pipe */
  200.         puts("Cannot construct pipe.");
  201.     signal(16, sig16);
  202.     sig16cnt = 0;
  203.     signal(SIGALRM, sig14);
  204.     if (ac < 2) {    /* must at least have telno arg */
  205.         prf(connmsg[8]);    /* usage message */
  206.         exit(8);
  207.     }
  208.     telno = av[1];
  209.     av += 2;
  210.     ac -= 2;
  211.     for (; ac > 0; av++) {
  212.         if (equal(*av, "-t")) {    /* dialout to terminal (direct?) */
  213.             dout = 1;
  214.             --ac;
  215.             continue;
  216.         }
  217.         if (ac < 2)    /* just one remaining argument is meaningless */
  218.             break;
  219.         if (equal(*av, "-s"))    /* speed (baud rate) */
  220.             lspeed = *++av;
  221.         else if (equal(*av, "-l"))    /* comm line override */
  222.             devcul = *++av;
  223.         else if (equal(*av, "-a"))    /* ACU override */
  224.             devcua = *++av;
  225.         else if (equal(*av, "-d"))    /* system description file */
  226.             sysdesfl = *++av;    
  227.         else
  228.             break;
  229.         ac -= 2;
  230.     }
  231.     if ((sdf = fopen(sysdesfl, "r")) == NULL)
  232.         printf("Cannot open system description file \"%s\".", sysdesfl);
  233.     fgets(prompt, 16, sdf);        /* read the system prompt string */
  234.     prompt[strlen(prompt) - 1] = '\0';
  235.     fgets(pt_tmplt, 128, sdf);    /* get the ~%put template string */
  236.     pt_tmplt[strlen(pt_tmplt) - 1] = '\0';
  237.     fgets(tk_tmplt, 128, sdf);    /* get the ~%take template string */
  238.     tk_tmplt[strlen(tk_tmplt) - 1] = '\0';
  239.     fclose(sdf);
  240.  
  241.     if (!exists(devcua) || !exists(devcul))
  242.         exit(9);
  243.     ln = conn(devcul, devcua, telno);    /* make the connection */
  244.     if (ln < 0) {
  245.         prf("Connect failed: %s", connmsg[-ln]);
  246.         exit(-ln);
  247.     }
  248.     switch (atoi(lspeed)) {
  249.     case 110:
  250.         speed = B110; break;
  251.     case 150:
  252.         speed = B150; break;
  253.     default:
  254.     case 300:
  255.         speed = B300; break;
  256.     case 1200:
  257.         speed = B1200; break;
  258.     }
  259.     stbuf.sg_ispeed = speed;
  260.     stbuf.sg_ospeed = speed;
  261.     stbuf.sg_flags = EVENP|ODDP;
  262.     if (!dout)            /* if not dialout to terminal */
  263.         stbuf.sg_flags |= RAW;
  264.     ioctl(ln, TIOCSETP, &stbuf);            /* set parameters */
  265.     ioctl(ln, TIOCEXCL, (struct sgttyb *) NULL);    /* exclusive use mode */
  266.     ioctl(ln, TIOCHPCL, (struct sgttyb *) NULL);    /* hangup on close */
  267.     prf("Connected");
  268.     wt_pid = getpid();        /* make note of write process id */
  269.     if (dout)            /* if dialout to terminal */
  270.         fk = -1;
  271.     else
  272.         fk = fork();
  273.     rd_pid = fk;            /* make note of read process ID */
  274.     nhup = (int) signal(SIGINT, SIG_IGN);
  275.     if (fk == 0) {            /* if this is the child of above fork */
  276.         rd();            /* read from this line */
  277.         prf("/007Lost carrier");
  278.         exit(3);
  279.     }
  280.     mode(1);
  281.     wr();            /* this is parent process - write to line */
  282.     mode(0);
  283.     kill(fk, SIGKILL);    /* done - kill child reader */
  284.     wait((int *) NULL);    /* wait for it to die */
  285.     stbuf.sg_ispeed = 0;
  286.     stbuf.sg_ospeed = 0;
  287.     ioctl(ln, TIOCSETP, &stbuf);    /* set parameters */
  288.     prf("Disconnected");
  289.     exit(0);
  290. }
  291. /*
  292.  *  conn:  establish dial-out connection.
  293.  *  Example:  fd = conn("/dev/ttyh", "/dev/dn1", "4500");
  294.  *  Returns descriptor open to tty for reading and writing.
  295.  *  Negative values (-1 ... -7) denote errors in connmsg.
  296.  *  Uses alarm and fork/wait; requires sig14 handler.
  297.  *  Be sure to disconnect tty when done, via HUPCL or stty 0.
  298.  */
  299. conn(dev, acu, telno)
  300. char *dev, *acu, *telno;
  301. {
  302.     struct sgttyb stbuf;
  303.     extern errno;
  304.     char *p, *q, b[30];
  305.     int er, fk, dn, dh, t;
  306.  
  307.     er = 0;
  308.     fk = (-1);
  309.     if ((dn = open(acu, 1)) < 0) {
  310.         er = (errno == 6 ? 1 : 5);    /* "line busy" or "acu access"*/
  311.         goto X;
  312.     }
  313.     if ((fk = fork()) == (-1)) {    /* if couldn't spawn child process */
  314.         er = 4;            /* "can't fork" */
  315.         goto X;
  316.     }
  317.     if (fk == 0) {            /* if this is child process */
  318.         open (dev, 2);        /* open line for read and write */
  319.         for (;;) pause();
  320.     }
  321.     xsleep(2);
  322.     /*
  323.      *    copy phone #, assure EON
  324.      */
  325.     p = b;
  326.     q = telno;
  327.     while (*p++ = (*q++))
  328.         ;            /* copy telno string to b[] */
  329.     p--;
  330.     if (*(p - 1) != '<') {        /* "<" is end-of-number */
  331.         if (*(p - 1) != '-') *p++ = '-';    /* "-" await dialtone */
  332.         *p++ = '<';
  333.     }
  334.     t = p - b;        /* get length of string */
  335.     xalarm(5 * t);        /* set watchdog timer */
  336.     t = write(dn, b, t);    /* write telno to ACU */
  337.     xalarm(0);
  338.     if (t < 0) {
  339.         er = 2;        /* "call dropped" */
  340.         goto X;
  341.     }
  342.     /* close(dn) */
  343.     xalarm(40);    /* was 5; sometimes missed carrier */
  344.     dh = open(dev, 2);        /* open line for read/write */
  345.     xalarm(0);
  346.     if (dh < 0) {
  347.         er = (errno == 4 ? 3 : 6);    /* "no carrier"or"tty access" */
  348.         goto X;
  349.     }
  350. /* ?!?    ioctl(TIOCGETP, ln, &stbuf);        /* get parameters */
  351.     ioctl(dh, TIOCGETP, &stbuf);
  352.     stbuf.sg_flags &= ~ECHO;
  353.     xalarm(10);
  354.     ioctl(dh, TIOCSETP, &stbuf);        /* set parameters */
  355.     ioctl(dh, TIOCHPCL, (struct sgttyb *) NULL);    /* hangup on close */
  356.     xalarm(0);
  357.     X:
  358.     if (er) close(dn);
  359.     if (fk != (-1)) {    /* if there is a child process */
  360.         kill (fk, SIGKILL);
  361.         xalarm(10);
  362.         while ((t = wait((int *) NULL)) != (-1) && t != fk)
  363.             ;            /* wait for child to die */
  364.         xalarm(0);
  365.     }
  366.     return (er ? -er : dh);
  367. }
  368. /*
  369.  *  wr:  write to remote:  0 -> line (0 = stdin)
  370.  *  ~.  terminate
  371.  *  ~<file  send file
  372.  *  ~!  local login-style shell
  373.  *  ~!cmd  execute cmd locally
  374.  *  ~$proc  execute proc locally, send output to line
  375.  *  ~%cmd  execute builtin cmd (put and take)
  376.  */
  377. wr()
  378. {
  379.     int ds, fk, lcl, x;
  380.     char *p, b[600];
  381.  
  382.     pipefp = fdopen(pipefd[1], "w");    /* open write strm into pipe */
  383.     for (;;) {
  384.         p = b;
  385.         while (rdc(0) == 1 || (errno == EINTR && rdc(0) == 1)) {
  386.                         /* reads into c from stdin */
  387.             if (p == b) lcl = (c == '~');    /* line "~..." local */
  388.             if (p == b + 1 && b[0] == '~') lcl = (c != '~');
  389.                     /* ...unless starts with "~~..." */
  390.             if (c == 0) c = 0177;    /* map NUL to DEL */
  391.             if (!lcl) {
  392.                 if (wrc(ln) == 0) {    /* write char to line */
  393.                     prf("line gone"); return;
  394.                 }
  395.             }
  396.             if (lcl) {
  397.                 if (c == 0177) c = tkill;    /* line kill */
  398.                 if (c == '\r' || c == '\n') goto A;
  399.                     /* break out of transmit loop */
  400.                 if (!dout) wrc(0);
  401.                     /* if not dialout, echo char to stdin */
  402.             }
  403.             *p++ = c;
  404.             if (c == terase) {    /* if erase character */
  405.                 p = p - 2;    /* back up one space */
  406.                 if (p < b) p = b;
  407.             }
  408.             if (c == tkill || c == 0177 || c == '\r' || c == '\n')
  409.                 p = b;        /* reuse line */
  410.         }
  411.         return;
  412.         A:
  413.         if (!dout) echo("");
  414.         *p = 0;
  415.         switch (b[1]) {
  416.         case '.':
  417.         case '\004':        /* ^D is EOF */
  418.             return;        /* finished with call */
  419.         case '!':        /* escape to shell */
  420.         case '$':        /* transmit stdout of foll. cmd */
  421.             fk = fork();
  422.             if (fk == 0) {    /* if this is child... */
  423.                 close(1);
  424.                 dup(b[1] == '$' ? ln : 2);
  425.                 close(ln);
  426.                 mode(0);
  427.                 if (!nhup) signal(SIGINT, SIG_DFL);
  428.                 if (b[2] == 0) execl("/bin/sh", "-", 0);
  429.                 else execl("/bin/sh", "sh", "-c", b + 2, 0);
  430.                 prf("Can't execute shell");
  431.                 exit(~0);
  432.             }
  433.             if (fk != (-1)) {
  434.                 while (wait(&x) != fk)
  435.                     ;
  436.             }
  437.             mode(1);
  438.             if (b[1] == '!') echo("!");
  439.             else {
  440.                 if (dout) echo("$");
  441.             }
  442.             break;
  443.         case '<':            /* read file out the line */
  444.             if (b[2] == 0) break;
  445.             if ((ds = open(b + 2, 0)) < 0) {
  446.                 prf("Can't divert %s", b + 1);
  447.                 break;
  448.             }
  449.             intr = x = 0;
  450.             mode(2);
  451.             if (!nhup) signal(SIGINT, sig2);
  452.             while (!intr && rdc(ds) == 1) {
  453.                 if (wrc(ln) == 0) {
  454.                     x = 1;
  455.                     break;
  456.                 }
  457.             }
  458.             signal(SIGINT, SIG_IGN);
  459.             close(ds);
  460.             mode(1);
  461.             if (x) return;
  462.             if (dout) echo("<");
  463.             break;
  464.         case '%':        /* put and take commands */
  465.             dopercen(&b[2]);
  466.             break;
  467.         default:
  468.             prf("Use `~~' to start line with `~'");
  469.         }
  470.         continue;
  471.     }
  472. }
  473. dopercen(line)
  474. register char *line;
  475. {
  476.     char cmd_line[256];
  477.     char *args[10];
  478.     register narg, f;
  479.  
  480.     for (narg = 0; narg < 10;) {        /* collect arguments */
  481.         while (*line == ' ' || *line == '\t')
  482.             line++;            /* scan past white space */
  483.         if (*line == '\0')
  484.             break;
  485.         args[narg++] = line;        /* there is an argument here */
  486.         while (*line != '\0' && *line != ' ' && *line != '\t')
  487.             line++;            /* find end of argument */
  488.         if (*line == '\0')
  489.             break;
  490.         *line++ = '\0';            /* terminate argument string */
  491.     }
  492.     if (equal(args[0], "take")) {
  493.         if (narg < 2) {
  494.             prf("usage: ~%%take from [to]");
  495.             return;
  496.         }
  497.         if (narg < 3)
  498.             args[2] = args[1];
  499.         fprintf(pipefp, "~>:%s\n", args[2]);    /* put filnam in pipe */
  500.         fflush(pipefp);            /* and make sure rd() sees it */
  501.         sprintf(cmd_line, tk_tmplt, args[1], args[1], args[1], args[1]);
  502.             /* substitute "from" filname for all "%s" in template */
  503.         do_macro(cmd_line, f);    /* process ~%take command mac */
  504.         return;
  505.     }
  506.     else if (equal(args[0], "put")) {
  507.         if (narg < 2) {
  508.             prf("usage: ~%%put from [to]");
  509.             return;
  510.         }
  511.         if (narg < 3)
  512.             args[2] = args[1];
  513.         if ((f = open(args[1], 0)) < 0) {    /* open "from" file */
  514.             prf("cannot open: %s", args[1]);    /* for read */
  515.             return;
  516.         }
  517.         sprintf(cmd_line, pt_tmplt, args[2], args[2], args[2], args[2]);
  518.             /* substitute "to" filename for all "%s" in template */
  519.         do_macro(cmd_line, f);    /* process ~%put macro string */
  520.         return;
  521.     }
  522.     prf("~%%%s unknown\n", args[0]);
  523. }
  524. equal(s1, s2)
  525. register char *s1, *s2;
  526. {
  527.     while (*s1++ == *s2)
  528.         if (*s2++ == '\0')
  529.             return(1);
  530.     return(0);
  531. }
  532. wrln(s)
  533. register char *s;
  534. {
  535.     while (*s)
  536.         write(ln, s++, 1);
  537. }
  538. /*
  539.  *  rd:  read from remote:  line -> 1 (1 = stdout).
  540.  *  catch:
  541.  *  ~>[>][:][file]
  542.  *  stuff from file...
  543.  *  ~>  (ends diversion)
  544.  */
  545. rd()
  546. {
  547.     int ds, slnt;
  548.     char *p, *q, b[600];
  549.     char eofstr[32];    /* array of EOF identifier character string */
  550.     int i, j;        /* indices used to pick out EOF string */
  551.  
  552.     pipefp = fdopen(pipefd[0], "r");    /* open pipe end for reading */
  553.     for (i = 2; (tk_tmplt[i - 2] != '~') && (tk_tmplt[i - 1] != '{'); i++)
  554.         ;        /* find start of EOF definition string */
  555.     for (j = i; (tk_tmplt[j] != '~') && (tk_tmplt[j + 1] != '}'); j++)
  556.         ;        /* find end of EOF definition string */
  557.     strncpy(eofstr, tk_tmplt + i, j - i);    /* copy EOF string from tmplt */
  558.     eofstr[j - i] = '\0';            /* terminate the EOF string  */
  559.  
  560.     p = b;
  561.     ds = (-1);
  562.     while (rdc(ln) == 1 || (errno == EINTR && rdc(ln) == 1)) {
  563.                         /* for each character... */
  564.         if (ds < 0) slnt = 0;
  565.         if (!slnt) wrc(1);    /* if not silent, write to stdout */
  566.         *p++ = c;
  567.         *p = '\0';        /* make sure legitimate string */
  568.         if (!strcmp(prompt, b))    /* if this looks like a prompt... */
  569.             kill (wt_pid, 16);    /* send signal 16 to wr() */
  570.         if (c != '\n') continue;
  571.                         /*** Complete lines ***/
  572.         q = p;
  573.         p = b;    /* if newline, reset line */
  574.  
  575.         if (*(q - 2) == '\r') {    /* get rid of CR, if there */
  576.             q--;
  577.             *(q - 1) = (*q);
  578.         }
  579.         if (ds >= 0) {    /* if we are currently redirecting input... */
  580.             if (strncmp(eofstr, b, strlen(eofstr))){/* if not EOF */
  581.                 write(ds, b, q - b);    /* write ths ln to fl */
  582.                 continue;            /* gt nxt lin */
  583.             }
  584.                         /*** Hit EOF ***/
  585.             close(ds);
  586.             ds = (-1);    /* remember that we are not redirectn */
  587.             write(1, b, q - b);    /* might as well echo EOF ln. */
  588. /*            write(1, CRLF, sizeof(CRLF));    /* seems too much */
  589.             write(1, "\r", 1);
  590.             slnt = 0;
  591.         }
  592.         else {    /* we are not redirecting now - see if we should start*/
  593.             if (!sig16cnt)    /* if we have not received signal to */
  594.                 continue;    /* read pipe & redirect, done */
  595.             sig16cnt = 0;    /* reset for next time around */
  596.                         /*** Start redirection ***/
  597.             fgets(b, 64, pipefp);    /* get local command */
  598.             b[strlen(b) - 1] = '\0';    /* end string w/o \n */
  599.  
  600.             slnt = 0;
  601.             q = b + 2;
  602.             if (*q == '>') q++;
  603.             if (*q == ':') {
  604.                 slnt = 1;
  605.                 q++;
  606.             }
  607.             if (*q == 0) {
  608.                 ds = (-1);
  609.                 continue;
  610.             }
  611.             if (b[2] != '>' || (ds = open(q, 1)) < 0)
  612.                 ds = creat(q, 0644);
  613.             lseek(ds, (long) 0, 2);
  614.             if (ds < 0)
  615.                 prf("Can't divert %s", b + 1);
  616.         }
  617.     }
  618.     perror("read perror");
  619. }
  620. struct {char lobyte; char hibyte; };    /* sic - but why??? */
  621. mode(f)
  622. {
  623.     struct sgttyb stbuf;
  624.  
  625.     if (dout) return;
  626.     ioctl(0, TIOCGETP, &stbuf);    /* Get parameters */
  627.     tkill = stbuf.sg_kill;
  628.     terase = stbuf.sg_erase;
  629.     if (f == 0) {
  630.         stbuf.sg_flags &= ~RAW;
  631.         stbuf.sg_flags |= ECHO | CRMOD;
  632.     }
  633.     if (f == 1) {
  634.         stbuf.sg_flags |= RAW;
  635. /*        stbuf.sg_flags &= ECHO | CRMOD;    /* sic, but isn't it wrong? */
  636.         stbuf.sg_flags &= ~(ECHO | CRMOD);
  637.     }
  638.     if (f == 2) {
  639.         stbuf.sg_flags &= ~RAW;
  640.         stbuf.sg_flags &= ~(ECHO | CRMOD);
  641.     }
  642.     ioctl(0, TIOCSETP, &stbuf);    /* set parameters */
  643. }
  644. echo(s)
  645. char *s;
  646. {
  647.     char *p;
  648.     for (p = s; *p; p++)
  649.         ;
  650.     if (p > s) write(0, s, p - s);
  651.     write(0, CRLF, sizeof(CRLF));
  652. }
  653. prf(f, s)
  654. char *f;
  655. char *s;
  656. {
  657.     fprintf(stderr, f, s);
  658.     fprintf(stderr, CRLF);
  659. }
  660. exists(devname)
  661. char *devname;
  662. {
  663.     if (access(devname, 0) == 0)
  664.         return(1);
  665.     prf("%s does not exist", devname);
  666.     return(0);
  667. }
  668.